import socket

socket.setdefaulttimeout(5.0)
import urllib
import os
import requests

from config import (
    DOWNLOAD_DIR,
    TUMBLR_DOWNLOAD_DIR,
    TUMBLR_PHOTO_DIR,
    TUMBLR_VIDEO_DIR,
)
from model import News, TResource
from dbhelper import DBHelper
import utils

__all__ = ['Downloader', 'TumblrDownloader']


class Downloader:
    def __init__(self, dir=None):
        self.url = None
        self.dir = dir and dir or DOWNLOAD_DIR
        self.check_download_dir()
        self.news = None
        self.db = DBHelper()

    def check_download_dir(self):
        if not os.path.exists(self.dir):
            os.mkdir(self.dir)

    def set_task(self, obj):
        if not obj or not obj.link: return False

        self.news = obj
        self.news.file = os.path.join(self.dir, obj.link.split('/')[-1])

        if os.path.exists(self.news.file) and os.path.getsize(
                self.news.file) == int(self.news.size):
            print '%s Already downloaded, skipping' % self.news.file
            self.db.update(
                News, {'status': 1,
                       'file': self.news.file},
                news_id=self.news.news_id)
            return

        print 'Start Download file: %s' % self.news.file
        try:
            urllib.urlretrieve(obj.link, self.news.file, self.show_progress)
        except Exception, e:
            self.db.update(News, {'status': -1}, news_id=self.news.news_id)
            print e

    def show_progress(self, block, blocksize, filesize):
        """
        @block    size of downloaded file
        @blocksize          size of block
        @filesize           size of remote file
        """
        per = 100.0 * block * blocksize / filesize
        if per > 100:
            per = 100
        print '%.2f%%\r' % per,

        if per == 100:
            self.db.update(
                News, {'status': 1,
                       'file': self.news.file},
                news_id=self.news.news_id)
            print 'Download completed: %s' % self.news.file


class TumblrDownloader(object):
    def __init__(self, dir=None):
        self.check_download_dir(TUMBLR_PHOTO_DIR)
        self.check_download_dir(TUMBLR_VIDEO_DIR)
        self.db = DBHelper()

        self.timeout = 10
        self.retry = 3
        self.max_num = 200

    def run(self):
        self.download()

    def get_resources(self):
        resources = self.db.select(TResource, limit=self.max_num, status=0)
        return resources

    def get_file_name(self, resource):
        if resource.medium_type == 'video':
            return str(resource.id) + '.mp4'
        elif resource.medium_type == 'photo':
            url = resource.url
            suffix = url.split(".")[-1]
            return str(resource.id) + "." + suffix

    def download(self):
        resources = self.get_resources()
        for r in resources:
            file_path = ''
            file_name = self.get_file_name(r)

            if not file_name:
                continue

            if r.medium_type == 'photo':
                file_dir = os.path.join(TUMBLR_PHOTO_DIR, r.site)
                utils.ensure_path(file_dir)

                file_path = os.path.join(file_dir, file_name)
            elif r.medium_type == 'video':
                file_dir = os.path.join(TUMBLR_VIDEO_DIR, r.site)
                utils.ensure_path(file_dir)

                file_path = os.path.join(file_dir, file_name)
            else:
                return

            self.download_file(r.url, file_path)

            if os.path.isfile(file_path):
                self.db.update(TResource, {'status': 1}, id=r.id)

    def download_file(self, url, path):
        if os.path.isfile(path):
            return

        print("Downloading %s\n" % url)
        retry_times = 0
        while retry_times < self.retry:
            try:
                resp = requests.get(url, stream=True, timeout=self.timeout)
                if resp.status_code == 403:
                    retry_times = self.retry
                    print("Access Denied when retrieve %s.\n" % url)
                    # raise Exception("Access Denied")
                with open(path, 'wb') as fh:
                    for chunk in resp.iter_content(chunk_size=1024):
                        fh.write(chunk)
                break
            except:
                # try again
                pass
            retry_times += 1
        else:
            try:
                os.remove(path)
            except OSError:
                pass
            print("Failed to retrieve %s.\n" % url)

    def check_download_dir(self, path=None):
        if not path:
            path = self.dir

        if not os.path.exists(path):
            os.makedirs(path)


if __name__ == '__main__':
    d = Downloader('.')
    n = News()
    n.link = 'http://yiapi.xinli001.com/fm/media-url/0/99390083'
    d.set_task(n)
